package edu.ynu.se.xiecheng.achitectureclass.service;

import edu.ynu.se.xiecheng.achitectureclass.dao.LightDataRepository;
import edu.ynu.se.xiecheng.achitectureclass.dao.DeviceRepository;
import edu.ynu.se.xiecheng.achitectureclass.dao.TokenRepository;
import edu.ynu.se.xiecheng.achitectureclass.dto.LightDataDTO;
import edu.ynu.se.xiecheng.achitectureclass.entity.LightData;
import edu.ynu.se.xiecheng.achitectureclass.entity.Device;
import edu.ynu.se.xiecheng.achitectureclass.entity.Token;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.core.ParameterizedTypeReference;
import org.springframework.http.*;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Service;
import org.springframework.util.LinkedMultiValueMap;
import org.springframework.util.MultiValueMap;
import org.springframework.web.client.RestTemplate;

import java.util.*;
import java.util.stream.Collectors;

@Slf4j
@Service
@RequiredArgsConstructor
public class LightDataService {
    private final LightDataRepository lightDataRepository;
    private final DeviceRepository deviceRepository;
    private final TokenRepository tokenRepository;
    private final RestTemplate restTemplate;
    private static final String TOKEN_TYPE_FBOX = "FBOX";

    public List<LightDataDTO> getLightData(Date start, Date end) {
        return lightDataRepository.findByCreateTimeBetween(start, end)
                .stream()
                .map(this::convertToDTO)
                .collect(Collectors.toList());
    }

    private LightDataDTO convertToDTO(LightData data) {
        LightDataDTO dto = new LightDataDTO();
        dto.setId(data.getId());
        dto.setValue(data.getValue());
        dto.setCreateTime(data.getCreateTime());
        dto.setDeviceId(data.getDevice().getId());
        dto.setDeviceName(data.getDevice().getName());
        dto.setUnit(data.getDevice().getUnit());
        return dto;
    }

    @Scheduled(initialDelay = 30000, fixedRate = 1800000)
    public void collectLightData() {
        List<Device> lightDevices = deviceRepository.findAll().stream()
                .filter(device -> "SOIL_SENSOR".equals(device.getDeviceType()) && 
                        "327061586065758012".equals(device.getSerialNumber()))
                .collect(Collectors.toList());

        for (Device device : lightDevices) {
            try {
                log.info("正在处理设备: {}, 序列号: {}", device.getName(), device.getSerialNumber());
                
                String fboxToken = ensureFboxToken();
                
                String url = "https://fbox360.com/api/v2/dmon/value/get?boxNo=300822040454";
                HttpHeaders headers = new HttpHeaders();
                headers.setBearerAuth(fboxToken);
                headers.setContentType(MediaType.APPLICATION_JSON);
                
                Map<String, Object> requestBody = new HashMap<>();
                requestBody.put("ids", Collections.singletonList(device.getSerialNumber()));
                
                HttpEntity<Map<String, Object>> request = new HttpEntity<>(requestBody, headers);
                
                ResponseEntity<List<Map<String, Object>>> response = restTemplate.exchange(
                    url,
                    HttpMethod.POST,
                    request,
                    new ParameterizedTypeReference<>() {}
                );
                
                if (response.getStatusCode() == HttpStatus.OK && response.getBody() != null && !response.getBody().isEmpty()) {
                    Map<String, Object> data = response.getBody().get(0);
                    String id = (String) data.get("id");
                    String name = (String) data.get("name");
                    double value = Double.parseDouble(data.get("value").toString());
                    
                    LightData lightData = new LightData();
                    lightData.setDevice(device);
                    lightData.setName(name);
                    lightData.setValue(value);
                    lightData.setCreateTime(new Date());
                    lightDataRepository.save(lightData);
                    log.info("成功保存光照强度数据: {}", value);
                }
            } catch (Exception e) {
                log.error("采集光照强度数据失败: " + device.getSerialNumber(), e);
            }
        }
    }

    private String ensureFboxToken() {
        Token token = tokenRepository.findByTokenType("FBOX")
                .orElse(new Token());

        if (token.getAccessToken() != null && token.getExpireTime() != null 
                && token.getExpireTime().after(new Date())) {
            return token.getAccessToken();
        }

        String url = "https://fbox360.com/idserver/core/connect/token";
        
        HttpHeaders headers = new HttpHeaders();
        headers.setContentType(MediaType.APPLICATION_FORM_URLENCODED);
        
        MultiValueMap<String, String> map = new LinkedMultiValueMap<>();
        map.add("grant_type", "client_credentials");
        map.add("client_id", "68db2e8bda8d47b5b5db7eaf71c7dcdd");
        map.add("client_secret", "76dc724c95004acab25482d344dab407");
        map.add("scope", "fbox");
        
        HttpEntity<MultiValueMap<String, String>> request = new HttpEntity<>(map, headers);
        
        try {
            ResponseEntity<Map> response = restTemplate.exchange(
                    url,
                    HttpMethod.POST,
                    request,
                    Map.class
            );

            if (response.getStatusCode() == HttpStatus.OK && response.getBody() != null) {
                String accessToken = (String) response.getBody().get("access_token");
                int expiresIn = (Integer) response.getBody().get("expires_in");
                
                token.setAccessToken(accessToken);
                token.setExpireTime(new Date(System.currentTimeMillis() + expiresIn * 1000L));
                token.setTokenType("FBOX");
                tokenRepository.save(token);
                
                return accessToken;
            }
        } catch (Exception e) {
            log.error("获取FBOX访问令牌失败", e);
            throw new RuntimeException("获取FBOX访问令牌失败");
        }
        
        throw new RuntimeException("获取FBOX访问令牌失败");
    }
} 